﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

namespace YawetagLib.Threading
{
    public sealed class ActionPool<T>
    {
        private const int MAX_SIGNAL_COUNT = 64;

        private ActionPool(Action<T> action, IEnumerable<T> arguments)
        {
            Action = action;
            Arguments = arguments;
        }

        public static void QueueAndWaitAll(Action<T> action, IEnumerable<T> arguments)
        {
            new ActionPool<T>(action, arguments).QueueAndWaitAll();
        }

        private void QueueAndWaitAll()
        {
            IList<T> queue = new List<T>();
            int index = 0;

            foreach (T a in Arguments)
            {
                queue.Add(a);
                index++;

                if (index == MAX_SIGNAL_COUNT)
                {
                    Process(queue);

                    queue.Clear();
                    index = 0;
                }
            }

            if (index != 0) { Process(queue); }
        }

        private void Process(IEnumerable<T> queue)
        {
            Queue = queue.ToArray();
            Signals = Queue.Select(i => new ManualResetEvent(false)).ToArray();

            for (int i = 0; i < Queue.Length; i++)
            {
                ThreadPool.QueueUserWorkItem(DoAction, i);
            }

            WaitHandle.WaitAll(Signals);
        }

        private void DoAction(object o)
        {
            int index = (int)o;

            Action(Queue[index]);
            Signals[index].Set();
        }

        private Action<T> Action { get; set; }
        private IEnumerable<T> Arguments { get; set; }

        private T[] Queue { get; set; }
        private ManualResetEvent[] Signals { get; set; }
    }
}
